/*
 * @(#)SimpleRead.java	1.12 98/06/25 SMI
 * 
 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 * 
 * Sun grants you ("Licensee") a non-exclusive, royalty free, license
 * to use, modify and redistribute this software in source and binary
 * code form, provided that i) this copyright notice and license appear
 * on all copies of the software; and ii) Licensee does not utilize the
 * software in a manner which is disparaging to Sun.
 * 
 * This software is provided "AS IS," without a warranty of any kind.
 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND
 * ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
 * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE
 * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS
 * BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES,
 * HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING
 * OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * This software is not designed or intended for use in on-line control
 * of aircraft, air traffic, aircraft navigation or aircraft
 * communications; or in the design, construction, operation or
 * maintenance of any nuclear facility. Licensee represents and
 * warrants that it will not use or redistribute the Software for such
 * purposes.
 */
package br.unifor.redes1.serial;

import java.io.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.comm.*;
import sun.misc.CRC16;

/**
 * Class declaration
 *
 *
 * @author
 * @version 1.8, 08/03/00
 */
public class ReadArq implements Runnable, SerialPortEventListener {

    static CommPortIdentifier portId;
    static Enumeration portList;
    InputStream inputStream;
    SerialPort serialPort;
    Thread readThread;
    FileOutputStream fOS;
    int i = 0;
    int bytesRead;
    int id = -1;
    int origem = -1;
    int destino = -1;
    String fileName;
    byte[] dados;
    byte[] bcc;

    /**
     * Method declaration
     *
     *
     * @param args
     *
     * @see
     */
    public static void main(String[] args) {
        boolean portFound = false;
        String defaultPort = "COM9";

        if (args.length > 0) {
            defaultPort = args[0];
        }

        portList = CommPortIdentifier.getPortIdentifiers();

        while (portList.hasMoreElements()) {
            portId = (CommPortIdentifier) portList.nextElement();
            if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                System.out.println(portId.getName());
                if (portId.getName().equals(defaultPort)) {
                    System.out.println("Found port: " + defaultPort);
                    portFound = true;
                    ReadArq reader = new ReadArq();
                }
            }
        }
        if (!portFound) {
            System.out.println("port " + defaultPort + " not found.");
        }

    }

    /**
     * Constructor declaration
     *
     *
     * @see
     */
    public ReadArq() {

        try {
            serialPort = (SerialPort) portId.open("SimpleReadApp", 2000);
        } catch (PortInUseException e) {
        }

        try {
            inputStream = serialPort.getInputStream();
        } catch (IOException e) {
        }

        try {
            serialPort.addEventListener(this);
        } catch (TooManyListenersException e) {
        }

        serialPort.notifyOnDataAvailable(true);

        try {
            serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
        } catch (UnsupportedCommOperationException e) {
        }



        readThread = new Thread(this);

        readThread.start();

    }

    /**
     * Method declaration
     *
     *
     * @see
     */
    public void run() {
    }

    /**
     * Method declaration
     *
     *
     * @param event
     *
     * @see
     */
    public void serialEvent(SerialPortEvent event) {
        switch (event.getEventType()) {

            case SerialPortEvent.BI:

            case SerialPortEvent.OE:

            case SerialPortEvent.FE:

            case SerialPortEvent.PE:

            case SerialPortEvent.CD:

            case SerialPortEvent.CTS:

            case SerialPortEvent.DSR:

            case SerialPortEvent.RI:

            case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
                break;

            case SerialPortEvent.DATA_AVAILABLE:
                Vector<Byte> pacoteRecebido = new Vector<Byte>();
                int numBytes;
                try {
                    while (inputStream.available() > 0) {
                        byte byteLido = (byte) inputStream.read();
                        System.out.println("[Byte Recebido]: " + byteLido);
                        if ((byteLido == ((byte) 0xF6))&&(inputStream.available()==0)) {
                            System.out.println("AVAILABLE = "+inputStream.available());
                            pacoteRecebido.add(new Byte(byteLido));
                            break;
                        } else {
                            pacoteRecebido.add(new Byte(byteLido));
                        }
                        bytesRead++;
                    }
                    System.out.println("====[Conteudo do Pacote]====");
                    for (int i = 0; i < pacoteRecebido.size(); i++) {
                        System.out.println((byte) pacoteRecebido.get(i));
                    }
                    if (this.calculaBCC(pacoteRecebido)) {
                        this.extractPackage(pacoteRecebido);
                        if (this.id == 0) {
                            fOS = new FileOutputStream(new File("C:\\" + this.fileName));
                        }
                        fOS.write(this.dados);
                    } else {
                        System.exit(0);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }

                break;
        }
    }

    private void extractPackage(Vector<Byte> v) {
        System.out.println("====Extaindo dados do Pacote====");
        int cont = 0;
        int contAux = 0;
        int contAux2 = 0;
        Byte lastElement;
        while (cont < v.size()) {
            if ((cont == 0)&&(v.get(cont).byteValue() == (byte) 0xF1)) {
                System.out.println("BYTE SYN RECEBIDO = " + v.get(cont).byteValue());
                cont++;
            }
            if ((cont == 1)&&(v.get(cont).byteValue() == (byte) 0xF2)) {
                System.out.println("BYTE SOH RECEBIDO = " + v.get(cont).byteValue());
                cont++;
            }
            if (cont == 2) {
                this.id = (int) v.get(cont).byteValue();
                cont++;
                System.out.println("ID PACOTE = " + this.id);
            } else if (cont == 3) {
                this.origem = (int) v.get(cont).byteValue();
                cont++;
                System.out.println("ENDERECO DE ORIGEM = " + this.origem);
            } else if (cont == 4) {
                this.destino = (int) v.get(cont).byteValue();
                cont++;
                System.out.println("ENDERECO DE DESTINO = " + this.destino);
            } else if (cont == 5) {
                if ((v.get(cont).byteValue() != (byte) 0xFA)&&(v.get(cont+1).byteValue() != (byte) 0xF3)) {
                    Vector<Byte> nomeArquivo = new Vector<Byte>();
                    while ((v.get(cont).byteValue() != (byte) 0xFA) || ((v.get(cont).byteValue() == (byte) 0xFA)) && (v.get(cont + 1).byteValue() == (byte) 0xFA)) {
                        //System.out.println("Pegando nome de arquivo byte = "+v.get(cont).byteValue()+" e proximo = "+v.get(cont+1).byteValue());
                        if ((v.get(cont).byteValue() == (byte) 0xFA) && (v.get(cont + 1).byteValue() == (byte) 0xFA)) {
                            nomeArquivo.add(v.get(cont));
                            //    System.out.println("Entrou no caso de DLE-DLE");
                            cont = cont + 2;
                            if(v.get(cont).byteValue() == (byte) 0xF3)
                            {
                                nomeArquivo.add(v.get(cont));
                                cont++;
                            }
                        } else {
                            nomeArquivo.add(v.get(cont));
                            cont++;
                        }
                    }
                    byte[] fileNameArr = new byte[nomeArquivo.size()];
                    for (int k = 0; k < nomeArquivo.size(); k++) {
                        fileNameArr[k] = nomeArquivo.get(k).byteValue();
                    }
                    this.fileName = new String(fileNameArr);
                    System.out.println("NOME DO ARQUIVO = " + this.fileName);
                    System.out.println("BYTE DLE RECEBIDO = " + v.get(cont).byteValue());
                    cont++;
                    System.out.println("BYTE STX/ETB RECEBIDO = " + v.get(cont).byteValue());
                    cont++;
                    contAux = cont;
//                    System.out.println("CONTAUX = " + contAux);
//                    System.out.println("CONT = " + cont);
                } else if (v.get(cont).byteValue() == (byte) 0xFA) {
                    System.out.println("BYTE DLE RECEBIDO = " + v.get(cont).byteValue());
                    cont++;
                    System.out.println("BYTE STX/ETB RECEBIDO = " + v.get(cont).byteValue());
                    cont++;
                    contAux = cont;
                }
            } else if (cont == contAux) {
                Vector<Byte> data = new Vector<Byte>();
                while ((v.get(cont).byteValue() != (byte) 0xFA) || ((v.get(cont).byteValue() == (byte) 0xFA)) && (v.get(cont + 1).byteValue() == (byte) 0xFA)) {
                    if ((v.get(cont).byteValue() == (byte) 0xFA) && (v.get(cont + 1).byteValue() == (byte) 0xFA)) {
                        data.add(v.get(cont));
                        cont++;
                        cont++;
                         if((v.get(cont).byteValue() == (byte) 0xF4)||(v.get(cont).byteValue() == (byte) 0xF5))
                            {
                                data.add(v.get(cont));
                                cont++;
                            }
                    } else {
                        data.add(v.get(cont));
                        cont++;
                    }
                }
                byte[] dadosArr = new byte[data.size()];
                for (int k = 0; k < data.size(); k++) {
                    dadosArr[k] = data.get(k).byteValue();
                }
                this.dados = dadosArr;
                for (int p = 0; p < this.dados.length; p++) {
                    System.out.println("BYTE DA DADOS: = " + this.dados[p]);
                }
                System.out.println("BYTE DLE RECEBIDO = " + v.get(cont).byteValue());
                cont++;
                System.out.println("BYTE STX RECEBIDO = " + v.get(cont).byteValue());
                cont++;
                contAux2 = cont;
            } else if (cont == contAux2) {
                System.out.println("ENTROU NO IF DO BCC");
                Vector<Byte> bccAux = new Vector<Byte>();
                while ((v.get(cont).byteValue() != (byte) 0xF6)||(v.get(cont).byteValue() == (byte) 0xF6)&&(cont<v.size()-1)) {
                    bccAux.add(v.get(cont));
                    System.out.println("BYTE BCC RECEBIDO = " + v.get(cont).byteValue());
                    cont++;
                }
                this.bcc = new byte[bccAux.size()];
                for (int h = 0; h < bccAux.size(); h++) {
                    this.bcc[h] = bccAux.get(h);
                }
            } else if (cont == (contAux2 + 2)) {
                System.out.println("BYTE PAD RECEBIDO = " + v.get(cont).byteValue());
                cont++;
            }
        }
    }

    private boolean calculaBCC(Vector<Byte> pacote) {
        boolean ret = false;
        int tamanhoPacote = pacote.size();
        CRC16 crc = new CRC16();
        byte[] bccValue = new byte[2];
        bccValue[0] = pacote.get(tamanhoPacote - 3);
        System.out.println("PRIMEIRO BYTE BCC = " + bccValue[0]);
        bccValue[1] = pacote.get(tamanhoPacote - 2);
        System.out.println("SEGUNDO BYTE BCC = " + bccValue[1]);
        // Remove os Bytes de BCC Temporariamente para o calculo
        System.out.println("PRIMEIRO BYTE DE BCC RETIRADO = "+pacote.remove(tamanhoPacote - 3));
        System.out.println("SEGUNDO BYTE DE BCC RETIRADO = "+pacote.remove(tamanhoPacote - 3));
        // Calculo do BCC
        for (int i = 0; i < pacote.size(); i++) {
            byte teste = (pacote.get(i).byteValue());
            crc.update(teste);
        }
        byte[] bccValueNow = this.converteIntToByte(crc.value);
        System.out.println("PRIMEIRO BYTE BCC NOW = " + bccValueNow[0]);
        System.out.println("SEGUNDO BYTE BCC NOW = " + bccValueNow[1]);
        for (int k = 0; k < bccValueNow.length; k++) {
            if (bccValue[k] == bccValueNow[k]) {
                ret = true;
            } else {
                ret = false;
            }
        }
        crc.reset();
        //Readiciona os Bytes do BCC ao pacote
        pacote.add(tamanhoPacote - 3, bccValue[0]);
        pacote.add(tamanhoPacote - 3, bccValue[1]);
        return ret;
    }

    public byte[] converteIntToByte(int a) {
        byte[] ret = null;
        ret = new byte[2];
        ret[0] = (byte) (a / 256);
        ret[1] = (byte) (a % 256);
        return ret;
    }
}




